using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;
using Risiko.State;
using Risiko.Logic;
using Risiko.Menu;


namespace Risiko.Rendering
{
  public struct Quadrant
  {
    public Rectangle Bounds;
    public State.Territory[] Territories;
  }

  /// <summary>
  /// This is a game component that implements IUpdateable.
  /// </summary>
  public abstract class MainGameRenderer : BaseRenderer
  {
    // Internal properties
    private Texture2D circle, board, arrow;
    protected Quadrant[] quadrants;

    private Rectangle[] cardSlots;

    public MainGameRenderer(Game game)
      : base(game)
    {
      // TODO: Construct any child components here
    }

    /// <summary>
    /// Allows the game component to perform any initialization it needs to before starting
    /// to run.  This is where it can query for any required services and load content.
    /// </summary>
    public override void Initialize()
    {
      gameState = Game.Services.GetService(typeof(State.State)) as State.State;
      gameBounds = Game.GraphicsDevice.Viewport.Bounds;

      // Build quadrants
      quadrants = new Quadrant[20];
      for (int i = 0; i < quadrants.Count(); ++i)
      {
        quadrants[i].Bounds = new Rectangle((i % 5) * 160, (i / 5) * 120, 200, 150);
        List<State.Territory> territories = new List<State.Territory>();
        gameState.board.IterTerritories(t =>
        {
          // Add all the territories that are included in the quadrant
          if (quadrants[i].Bounds.Contains((int)t.position.X, (int)t.position.Y))
            territories.Add(t);
        });
        quadrants[i].Territories = territories.ToArray();
      }

      // Card slots
      cardSlots = new Rectangle[gameState.playerStates[2].Cards.Count];
      for (int i = 0; i < gameState.playerStates[2].Cards.Count; i++)
        cardSlots[i] = new Rectangle(gameBounds.Center.X - 100 + (i * 80), gameBounds.Center.Y + 100, 74, 110);

      base.Initialize();
    }


    protected override void LoadContent()
    {
      circle = Game.Content.Load<Texture2D>(@"Images//Board//Circle2");
      board = Game.Content.Load<Texture2D>(@"Images//Board//RisikoMap");
      arrow = Game.Content.Load<Texture2D>(@"Images//Board//Arrow2");

      base.LoadContent();
    }

    /// <summary>
    /// Allows the game component to update itself.
    /// </summary>
    /// <param name="gameTime">Provides a snapshot of timing values.</param>
    public override void Update(GameTime gameTime)
    {
      base.Update(gameTime);
    }


    public override void UpdatePlaceReinforcements(GameTime gameTime)
    {
      // Animazione
      if (gameState.playerStates[(int)gameState.currentPlayer].MossaFatta)
      {
        // Inizia l'animazione
        gameState.playerStates[(int)gameState.currentPlayer].MossaAnimata = false;
        gameState.playerStates[(int)gameState.currentPlayer].timerAnimazione = 0.5;
        // Consuma la mossa registrata dal player
        gameState.playerStates[(int)gameState.currentPlayer].MossaFatta = false;
      }
      if (!gameState.playerStates[(int)gameState.currentPlayer].MossaAnimata)
      {
        if (gameState.playerStates[(int)gameState.currentPlayer].timerAnimazione <= 0)
        {
          // Termina l'animazione
          gameState.playerStates[(int)gameState.currentPlayer].MossaAnimata = true;
        }
        else
          gameState.playerStates[(int)gameState.currentPlayer].timerAnimazione -= gameTime.ElapsedGameTime.TotalSeconds;
      }

      // Input
      foreach (var g in cachedGestures)
      {
        switch (g.GestureType)
        {
          case GestureType.Tap:
            HandleTerritorySelection(g);
            break;
          case GestureType.DoubleTap:
            break;
        }
      }
    }


    public override void UpdateAttack(GameTime gameTime)
    {
      foreach (var g in cachedGestures)
      {
        switch (g.GestureType)
        {
          case GestureType.Tap:
            HandleTerritorySelection(g);
            break;
          case GestureType.DoubleTap:
            break;
        }
      }
    }

    public override void UpdateConquerMove(GameTime gameTime)
    {
      foreach (GestureSample g in cachedGestures)
      {
        switch (g.GestureType)
        {
          case GestureType.Tap:
            HandleTerritorySelection(g);
            break;
          case GestureType.DoubleTap:
            HandleTerritorySelection(g);
            break;
        }
      }
    }

    public override void UpdateStrategicMove(GameTime gameTime)
    {
      foreach (var g in cachedGestures)
      {
        switch (g.GestureType)
        {
          case GestureType.Tap:
            HandleTerritorySelection(g);
            break;
          case GestureType.DoubleTap:
            break;
        }
      }
    }

    #region INPUT
    /// <summary>
    /// Gestisce la selezione di un territorio tramite Tap
    /// </summary>
    /// <param name="gestureSample">Il GestureSample effettuato dall'utente</param>
    private void HandleTerritorySelection(GestureSample gestureSample)
    {
      // 1. Check if the user pressed on a territory
      State.TerritoryReference tRef = new TerritoryReference() { continentID = -1, territoryID = -1 };
      float minDistance = 40.0f;
      for (int i = 0; i < quadrants.Count(); ++i)
      {
        // Cycle quadrants first
        if (quadrants[i].Bounds.Contains(new Point((int)gestureSample.Position.X, (int)gestureSample.Position.Y)))
        {
          for (int j = 0; j < quadrants[i].Territories.Count(); ++j)
          {
            // Cycle territories in the tapped quadrant
            float currentDistance = Math.Abs(Vector2.Distance(gestureSample.Position, quadrants[i].Territories[j].position));
            if (currentDistance < minDistance)
            {
              minDistance = currentDistance;
              tRef = new TerritoryReference()
              {
                continentID = quadrants[i].Territories[j].continentID,
                territoryID = quadrants[i].Territories[j].territoryID
              };
            }
          }
        }
      }
      if (tRef.territoryID != -1 && minDistance < 40.0f)
      {
        // 2. A territory has been selected: publish it on InputEvents
        TouchedTerritory = new TouchedTerritory()
        {
          IsNull = false,
          territoryRef = tRef,
          gesture = gestureSample.GestureType
        };

        // IN ALTERNATIVA:
        //var tt = TouchedTerritory;
        //tt.IsNull = false;
        //TouchedTerritory = tt;
      }
    }


    //private void HandleCardSelection(GestureSample tap)
    //{
    //  for (int i = 0; i < cardSlots.Length; ++i)
    //  {
    //    Point p = new Point((int)tap.Position.X, (int)tap.Position.Y);
    //    if (cardSlots[i].Contains((int)tap.Position.X, (int)tap.Position.Y))
    //    {
    //      var c = gameState.playerStates[2].Cards[i];

    //      if (c.isSelected)
    //      {
    //        c.isSelected = false;
    //      }
    //      else
    //      {
    //        TouchedCard = new TouchedCard()
    //        {
    //          IsNull = false,
    //          territoryRef = new TerritoryReference() { continentID = c.territory.continentID, territoryID = c.territory.territoryID }
    //        };
    //        c.isSelected = true;
    //      }

    //      gameState.playerStates[2].Cards[i] = c;
    //    }
    //  }
    //}



    #endregion

    public override void Draw(GameTime gameTime)
    {
      base.Draw(gameTime);
    }

    public override void DrawBoard(GameTime gameTime)
    {
      State.PlayerState ownerInfo;

      // Draw board
      spriteBatch.Draw(board, Game.GraphicsDevice.Viewport.Bounds, Color.White);

      gameState.board.IterTerritories(t =>
        {
          // Draw territories
          var position = t.position;
          ownerInfo = gameState.playerStates[(int)t.owner];
          spriteBatch.Draw(circle, new Rectangle((int)position.X, (int)position.Y, 40, 40), null, ownerInfo.color, 0.0f, new Vector2(circle.Bounds.Center.X, circle.Bounds.Center.Y), SpriteEffects.None, 0.0f);

          // Draw links
          for (int k = 0; k < t.neighbors.Count(); ++k)
          {
            var linkStart = t.position;
            var linkEndTId = t.neighbors[k].territoryID;
            var linkEndCId = t.neighbors[k].continentID;
            var linkEnd = gameState.board.continents[linkEndCId].territories[linkEndTId].position;

            var linkAngle = (float)Math.Atan2(linkEnd.Y - linkStart.Y, linkEnd.X - linkStart.X);
            var linkLen = Vector2.Distance(linkStart, linkEnd);
            spriteBatch.Draw(whitePx, linkStart, null, Color.Gray, linkAngle, Vector2.Zero, new Vector2(linkLen, 1), SpriteEffects.None, 0.0f);
          }

          //spriteBatch.DrawString(font, t.territoryID.ToString(), position, Color.White, 0.0f, font.MeasureString(t.territoryID.ToString()) / 2, 1.0f, SpriteEffects.None, 0.1f);
          //spriteBatch.DrawString(font, ownerInfo.name, position + new Vector2(0, 15), ownerInfo.color, 0.0f, font.MeasureString(ownerInfo.name) / 2, 1.0f, SpriteEffects.None, 0.1f);
          //spriteBatch.DrawString(font, t.name, position + new Vector2(0, 15), Color.White, 0.0f, font.MeasureString(t.name) / 2, 1.0f, SpriteEffects.None, 0.1f);

          // Draw armies
          DrawCenteredMsg(font, t.armies.ToString(), position + Vector2.One, Color.Black, Vector2.One);
          DrawCenteredMsg(font, t.armies.ToString(), position, ownerInfo.color, Vector2.One);
          //spriteBatch.DrawString(font, t.armies.ToString(), position + new Vector2(20, -30), ownerInfo.color);
        });

      // Draw territory info
      var selectedTerritories = gameState.playerStates[(int)gameState.currentPlayer].tappedTerritories;
      if (selectedTerritories.Count > 0)
      {
        var terr = gameState.board.GetTerritory(selectedTerritories.Last());
        ownerInfo = gameState.playerStates[(int)terr.owner];
        spriteBatch.DrawString(font, "Territory: " + terr.name, Vector2.Zero, Color.Black);
        spriteBatch.DrawString(font, "Owner: " + ownerInfo.name, new Vector2(0, 30), ownerInfo.color);
        spriteBatch.DrawString(font, "Armies: " + terr.armies.ToString(), new Vector2(0, 60), Color.Red);
      }

      // Log
      if (gameState.Log.Count() > 0)
        spriteBatch.DrawString(font, gameState.Log.Last(), new Vector2(0, 460), Color.Black, 0.0f, Vector2.Zero, 0.5f, SpriteEffects.None, 1.0f);
    }


    public override void DrawPlaceReinforcements(GameTime gameTime)
    {
      if (!gameState.playerStates[(int)gameState.currentPlayer].MossaAnimata)
      {
        var t = gameState.playerStates[(int)gameState.currentPlayer].CurrArmiesPlacement.territory;
        var size = (int)(45 + (gameState.playerStates[(int)gameState.currentPlayer].timerAnimazione * 45));
        spriteBatch.Draw(circle, new Rectangle((int)t.position.X, (int)t.position.Y, size, size), null, gameState.playerStates[(int)gameState.currentPlayer].color, 0.0f, new Vector2(circle.Bounds.Center.X, circle.Bounds.Center.Y), SpriteEffects.None, 0.0f);
      }
    }


    public override void DrawAttack(GameTime gameTime)
    {
      // Draw attack arrow
      if (!gameState.playerStates[(int)gameState.currentPlayer].MossaAnimata)
      {
        var tFrom = gameState.board.GetTerritory(gameState.playerStates[(int)gameState.currentPlayer].CurrAttack.from);
        var tTo = gameState.board.GetTerritory(gameState.playerStates[(int)gameState.currentPlayer].CurrAttack.to);

        var linkStart = tFrom.position;
        var linkEnd = gameState.board.continents[tTo.continentID].territories[tTo.territoryID].position;
        var linkAngle = (float)Math.Atan2(linkEnd.Y - linkStart.Y, linkEnd.X - linkStart.X);

        spriteBatch.Draw(arrow, new Rectangle((int)tFrom.position.X, (int)tFrom.position.Y, 80, 80), null, Color.Red, linkAngle, new Vector2(arrow.Bounds.Center.X, arrow.Bounds.Center.Y), SpriteEffects.None, 0.0f);
      }

      // Draw territories involved in the attack
      var selectedTerritories = gameState.playerStates[(int)gameState.currentPlayer].tappedTerritories;
      for (int i = 0; i < selectedTerritories.Count; ++i)
      {
        Territory t = gameState.board.GetTerritory(selectedTerritories[i]);
        spriteBatch.Draw(circle, new Rectangle((int)t.position.X, (int)t.position.Y, 45, 45), null, Color.Yellow, 0.0f, new Vector2(circle.Bounds.Center.X, circle.Bounds.Center.Y), SpriteEffects.None, 0.0f);
      }
    }

    public override void DrawConquerMove(GameTime gameTime)
    {
      // Draw the territories that were involved in the attack
      Territory t1 = gameState.board.GetTerritory(gameState.playerStates[(int)gameState.currentPlayer].CurrAttack.from);
      Territory t2 = gameState.board.GetTerritory(gameState.playerStates[(int)gameState.currentPlayer].CurrAttack.to);

      spriteBatch.Draw(circle, new Rectangle((int)t1.position.X, (int)t1.position.Y, 45, 45), null, Color.Blue, 0.0f, new Vector2(circle.Bounds.Center.X, circle.Bounds.Center.Y), SpriteEffects.None, 0.0f);
      spriteBatch.Draw(circle, new Rectangle((int)t2.position.X, (int)t2.position.Y, 45, 45), null, Color.Blue, 0.0f, new Vector2(circle.Bounds.Center.X, circle.Bounds.Center.Y), SpriteEffects.None, 0.0f);
    }

    public override void DrawStrategicMove(GameTime gameTime)
    {
      if (gameState.playerStates[(int)gameState.currentPlayer].CurrMove.isValid)
      {
        // Draw the highlighted territories (after selection)
        Territory t1 = gameState.board.GetTerritory(gameState.playerStates[(int)gameState.currentPlayer].CurrMove.from);
        Territory t2 = gameState.board.GetTerritory(gameState.playerStates[(int)gameState.currentPlayer].CurrMove.to);

        spriteBatch.Draw(circle, new Rectangle((int)t1.position.X, (int)t1.position.Y, 45, 45), null, Color.Blue, 0.0f, new Vector2(circle.Bounds.Center.X, circle.Bounds.Center.Y), SpriteEffects.None, 0.0f);
        spriteBatch.Draw(circle, new Rectangle((int)t2.position.X, (int)t2.position.Y, 45, 45), null, Color.Blue, 0.0f, new Vector2(circle.Bounds.Center.X, circle.Bounds.Center.Y), SpriteEffects.None, 0.0f);
      }
      else
      {
        var selectedTerritories = gameState.playerStates[(int)gameState.currentPlayer].tappedTerritories;
        for (int i = 0; i < selectedTerritories.Count; ++i)
        {
          // Draw the selected territories (while selecting)
          Territory t = gameState.board.GetTerritory(selectedTerritories[i]);
          spriteBatch.Draw(circle, new Rectangle((int)t.position.X, (int)t.position.Y, 45, 45), null, Color.Yellow, 0.0f, new Vector2(circle.Bounds.Center.X, circle.Bounds.Center.Y), SpriteEffects.None, 0.0f);
        }
      }

    }
  }
}
